package cn.tedu.forum.user.webapi.service;

import cn.tedu.forum.pojo.dto.RegisterDTO;
import cn.tedu.forum.pojo.entity.UserInfo;
import cn.tedu.forum.commons.exception.ServiceException;
import cn.tedu.forum.pojo.vo.UserInfoStandardVO;
import cn.tedu.forum.user.webapi.cache.repo.IUserInfoCacheRepository;
import cn.tedu.forum.user.webapi.mapper.UserInfoMapper;
import cn.tedu.forum.user.service.IUserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

import static cn.tedu.forum.commons.response.ServiceCode.*;

/**
 * 用户基本信息业务处理实现类
 *
 * @author DunJu Zhou
 */

@Service
@Slf4j
public class UserInfoServiceImpl implements IUserInfoService {

    // 自动装配AdminMapper
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private IUserInfoCacheRepository userInfoCacheRepository;

    /**
     * 重建缓存的间隔时间，以分钟为单位
     */
    public static final Integer REBUILD_INTERVAL_TIME_IN_MINUTE = 1;

    @Override
    public Long register(RegisterDTO registerDTO) {
        /*
            通过参数userRegisterDTO中的phoneNumber,emailAddress，
            调用userInfoMapper的UserInfo getLoginInfoByPhoneNumber(phoneNumber,emailAddress)执行查询，
            并获取查询结果
         */
        log.debug("即将注册用户：{}", registerDTO);
        String phoneNumber = registerDTO.getPhoneNumber();
        UserInfoStandardVO savedUserInfo = userInfoMapper.getInfoByPhoneNumber(phoneNumber);
        // 判断查询结果是否【不为null】
        if (savedUserInfo != null) {
            // 是：表示电话或邮箱已经被占用，抛出ServiceException：增加用户失败，电话或邮箱已经被占用
            log.warn("用户注册失败，电话号码({})已经被占用", phoneNumber);
            throw new ServiceException(CONFLICT, "增加用户失败，电话号码已经被占用！");
        }

        // 以参数addNewUserDTO中的password作为明文，执行加密，得到密文密码
        /*String rawPassword = userRegisterDTO.getPassword();
        String encodedPassword = globalPasswordEncoder.encode(rawPassword);
        log.debug("已对密码进行加密处理，原密码为={}，加密后的密码为={}", rawPassword, encodedPassword);*/

        // 创建新的UserInfo对象
        UserInfo userInfo = new UserInfo();
        /*
            为UserInfo对象的属性赋值：
            username = null
            nickname 来自参数addNewUserDTO
            phoneNumber 来自参数addNewUserDTO
            emailAddress 来自参数addNewUserDTO（如未提供则为null）
            password = 密文密码
            avatar, profile = null
            isEnable = 1
            lastLoginIp = null
            loginCount = 0
            gmtLastLogin = null
            gmtCreate, gmtModified = LocalDateTime.now()
         */
        LocalDateTime now = LocalDateTime.now();
        userInfo.setNickname(registerDTO.getNickname())
                .setPassword(registerDTO.getPassword())
                .setPhoneNumber(phoneNumber)
                .setProfile("暂无个人简介")
                .setAvatarUrl("user/orgAvatar.jpg")
                .setGender(0)
                .setBalance(new BigDecimal("0.00"))
                .setEnable(1)
                .setLoginCount(0)
                .setGmtCreate(now)
                .setGmtModified(now);
        //if (emailAddress!=null) userInfo.setEmailAddress(emailAddress);

        // 调用userInfoMapper对象的int insert(UserInfo userInfo)方法插入用户数据，并获取返回值
        log.debug("即将注册用户的信息：{}", userInfo);
        int rows = userInfoMapper.insert(userInfo);
        // 判断返回值是否不为1
        if (rows != 1) {
            // 抛出ServiceException：服务器忙，请稍后再次尝试
            log.warn("服务器忙，请稍后再次尝试！");
            throw new ServiceException(INTERNAL_SERVER_ERROR, "服务器忙，请稍后再次尝试！");
        }
        return userInfo.getId();
    }

    /**
     * 打赏功能控制方法
     *
     * @param payerInfo 打赏者（付款人）基本信息
     * @param payeeInfo 被打赏者（收款人）基本信息
     * @param amount    打赏金额
     */
    public void giveRewards(UserInfo payerInfo, UserInfo payeeInfo, BigDecimal amount) {
        BigDecimal balOfPayer = userInfoMapper.getBalanceById(payerInfo.getId());
        BigDecimal balOfPayee = userInfoMapper.getBalanceById(payeeInfo.getId());
        if (balOfPayer.compareTo(amount) < 0) {
            log.warn("打赏失败，余额({})不足", balOfPayer);
            throw new ServiceException(CONFLICT, "打赏失败，余额不足！");
        }
        balOfPayer = balOfPayer.subtract(amount);
        balOfPayee = balOfPayee.add(amount);
        int rows1 = userInfoMapper.updateBalanceById(payerInfo.getId(), balOfPayer);
        int rows2 = userInfoMapper.updateBalanceById(payeeInfo.getId(), balOfPayee);
        // 判断返回值是否不为1
        if (rows1 != 1 || rows2 != 1) {
            // 抛出ServiceException：服务器忙，请稍后再次尝试
            log.warn("服务器忙，请稍后再次尝试！");
            throw new ServiceException(INTERNAL_SERVER_ERROR, "服务器忙，请稍后再次尝试！");
        }
        log.debug("用户：{} 打赏了用户：{} {}元", payerInfo.getNickname(), payeeInfo.getNickname(), amount);
    }

    /**
     * 充值功能控制方法
     *
     * @param userInfo 用户基本信息
     * @param amount   充值金额
     */
    public void recharge(UserInfo userInfo, BigDecimal amount) {
        BigDecimal balance = userInfoMapper.getBalanceById(userInfo.getId());
        balance = balance.add(amount);
        int rows = userInfoMapper.updateBalanceById(userInfo.getId(), balance);
        if (rows != 1) {
            // 抛出ServiceException：服务器忙，请稍后再次尝试
            log.warn("服务器忙，请稍后再次尝试！");
            throw new ServiceException(INTERNAL_SERVER_ERROR, "服务器忙，请稍后再次尝试！");
        }
        log.debug("用户：{} 充值了{}元，充值后的余额为{}元", userInfo.getNickname(), amount, balance);
    }


    @Override
    public void initCache() {
        loadCache();
    }

    @Override
    public void rebuildCache() {
        // TODO 添加最低刷新时间限制
        // 读取“最近重建缓存”的时间
        Long recentRebuildTime = userInfoCacheRepository.getRecentRebuildTime();
        if (recentRebuildTime == null) {
            recentRebuildTime = 0L;
        }
        // 与当前时间对比，判断时间差是否小于xx分钟
        Long currentTimeMillis = System.currentTimeMillis();
        if (currentTimeMillis - recentRebuildTime < REBUILD_INTERVAL_TIME_IN_MINUTE * 60 * 1000) {
            // 是：两次重建缓存的间隔时间太短，则抛出异常
            throw new ServiceException(NOT_ACCEPTABLE, "重建缓存失败，重建缓存必须间隔至少" + REBUILD_INTERVAL_TIME_IN_MINUTE + "分钟！");
        }
        loadCache();
    }

    /**
     * 加载类别数据的缓存
     */
    private void loadCache() {
        // 1. 从数据库中读取类别列表
        List<UserInfoStandardVO> standardVOList = userInfoMapper.listDetails();
        // 2. 清除缓存的类别数据
        userInfoCacheRepository.clear();
        // 3. 将类别数据写入到缓存
        for (UserInfoStandardVO userInfoStandardVO : standardVOList) {
            userInfoCacheRepository.setUserInfo(userInfoStandardVO);
        }
        // 4. 写入最近重建缓存的时间
        userInfoCacheRepository.setRecentRebuildTime(System.currentTimeMillis());
    }

    /*@Override
    public UserInfo getInfoById(HttpSession session) {
        UserInfo currUser = (UserInfo) session.getAttribute("currUser");
        if (currUser == null) return null;
        return userInfoMapper.getInfoById(currUser.getId());
    }*/
}

